import pandas as pd
import plotly.express as px
import plotly.graph_objects as go
from pathlib import Path
import os
import re
import chardet
import numpy as np
import matplotlib as mpl
import json
import sys
import shutil
import math

# 设置中文字体支持
mpl.rcParams['font.sans-serif'] = ['SimHei']  # 用来正常显示中文标签
mpl.rcParams['axes.unicode_minus'] = False  # 用来正常显示负号


# 1. 增强型文件加载器（解决编码问题）
def detect_file_encoding(file_path):
    """检测文件编码"""
    with open(file_path, 'rb') as f:
        raw_data = f.read(10000)  # 读取前10000字节进行检测

    # 添加UTF-8 BOM检测
    if raw_data.startswith(b'\xef\xbb\xbf'):
        return 'utf-8-sig'

    result = chardet.detect(raw_data)
    encoding = result['encoding']
    confidence = result['confidence']
    print(f"📊 检测到编码: {encoding} (置信度: {confidence:.2%})")

    # 如果置信度低，尝试常见中文编码
    if confidence < 0.7:
        for enc in ['GB18030', 'GBK', 'GB2312', 'utf-8', 'latin1']:
            try:
                raw_data.decode(enc)
                print(f"✅ 备选编码 '{enc}' 可用")
                return enc
            except:
                continue
    return encoding if encoding else 'GB18030'


def load_statistics_csv(file_path):
    """加载统计局格式的CSV文件，处理特殊格式"""
    print(f"🔍 正在加载文件: {file_path}")

    # 检测文件编码
    encoding = detect_file_encoding(file_path)

    # 读取文件内容
    with open(file_path, 'r', encoding=encoding, errors='replace') as f:
        lines = f.readlines()

    # 提取元数据
    metadata = {}
    data_lines = []
    for line in lines:
        line = line.strip()
        if not line:
            continue
        if re.match(r'^(数据库|地区|时间|数据来源)[:：]', line):
            parts = re.split(r'[:：]', line, 1)
            if len(parts) == 2:
                key, value = parts
                metadata[key.strip()] = value.strip().rstrip(',')
        else:
            data_lines.append(line)

    # 处理数据部分
    if not data_lines:
        print("❌ 文件未包含有效数据")
        return None, None

    # 解析数据表
    try:
        # 处理可能的分隔符问题
        delimiter = ',' if ',' in data_lines[0] else '\t'

        # 创建DataFrame
        df = pd.DataFrame([line.split(delimiter) for line in data_lines])

        # 设置列名（第一行为标题）
        df.columns = df.iloc[0]
        df = df[1:]

        # 重置索引
        df.reset_index(drop=True, inplace=True)

        print(f"✅ 成功加载数据: {df.shape[0]}行 x {df.shape[1]}列")
        print("前5行数据预览:")
        print(df.head())
        return df, metadata
    except Exception as e:
        print(f"❌ 数据解析失败: {str(e)}")
        import traceback
        traceback.print_exc()
        return None, None


# 2. 数据预处理
def preprocess_consumption_data(df, metadata, output_dir):
    """预处理消费支出数据"""
    if df is None or df.empty:
        print("❌ 无效数据，无法处理")
        return None

    print("\n原始数据预览:")
    print(df.head())

    # 识别指标列
    indicator_col = None
    for col in df.columns:
        if '指标' in col:
            indicator_col = col
            break

    if indicator_col is None:
        print("⚠️ 未找到指标列，使用第一列作为指标")
        indicator_col = df.columns[0]

    # 识别年份列
    year_columns = []
    for col in df.columns:
        try:
            # 尝试匹配各种年份格式
            if re.search(r'\d{4}年?', str(col)):
                year_columns.append(col)
            elif re.search(r'^\d{4}$', str(col)):  # 纯数字年份
                year_columns.append(col)
        except:
            continue

    if not year_columns:
        print("❌ 未找到年份列，尝试自动识别")
        # 尝试将第一行作为年份
        if len(df.columns) > 1:
            year_columns = list(df.columns[1:])

    if not year_columns:
        print("❌ 无法识别年份列")
        return None

    print(f"📅 年份列: {year_columns}")

    # 筛选所需指标
    required_indicators = [
        '全体居民人均消费支出',
        '城镇居民人均消费支出',
        '农村居民人均消费支出'
    ]

    # 创建指标映射
    indicator_mapping = {
        '全体': '全体居民人均消费支出(元)',
        '城镇': '城镇居民人均消费支出(元)',
        '农村': '农村居民人均消费支出(元)'
    }

    # 查找匹配的指标行
    data_dict = {}
    found_indicators = []
    for _, row in df.iterrows():
        indicator = str(row[indicator_col]).strip()
        found = False

        for key, new_name in indicator_mapping.items():
            if key in indicator:
                # 提取数值数据
                values = {}
                for col in year_columns:
                    year_match = re.search(r'\d{4}', str(col))
                    if not year_match:
                        continue

                    year = year_match.group()
                    value_str = str(row[col]).replace(',', '').strip()

                    # 处理各种可能的非数字情况
                    if value_str in ['-', '—', 'NA', 'NaN', '']:
                        value = np.nan
                    else:
                        try:
                            value = float(value_str)
                        except:
                            value = np.nan

                    values[year] = value

                # 添加到数据字典
                data_dict[new_name] = values
                found = True
                found_indicators.append(indicator)
                break

        if found:
            print(f"✅ 找到指标: {indicator} -> {new_name}")

    if not data_dict:
        print("❌ 未找到所需指标")
        print("可用指标:")
        print(df[indicator_col].unique())
        return None

    # 创建整理后的DataFrame
    clean_df = pd.DataFrame(data_dict)
    clean_df['年份'] = clean_df.index.astype(str)

    # 重置索引
    clean_df.reset_index(drop=True, inplace=True)

    # 重新排序列
    clean_df = clean_df[['年份'] + list(indicator_mapping.values())]

    # 转换为数值类型
    for col in indicator_mapping.values():
        if col in clean_df.columns:
            clean_df[col] = pd.to_numeric(clean_df[col], errors='coerce')

    # 添加元数据
    clean_df.attrs['metadata'] = metadata

    # 按年份排序
    if '年份' in clean_df.columns:
        clean_df['年份'] = pd.to_numeric(clean_df['年份'], errors='coerce')
        clean_df = clean_df.dropna(subset=['年份'])
        clean_df = clean_df.sort_values('年份')
        clean_df['年份'] = clean_df['年份'].astype(int)

    print("\n✅ 数据预处理完成")
    print(f"时间范围: {clean_df['年份'].min()} - {clean_df['年份'].max()}")
    print("处理后的数据:")
    print(clean_df)

    # 确保输出目录存在
    output_dir.mkdir(parents=True, exist_ok=True)

    # 保存预处理后的数据到CSV用于调试
    debug_path = output_dir / "debug_clean_data.csv"
    clean_df.to_csv(debug_path, index=False, encoding='utf-8-sig')
    print(f"✅ 预处理数据已保存到: {debug_path}")

    return clean_df


# 3. 数据分析与可视化
def analyze_and_visualize(df, output_dir):
    """执行数据分析和可视化"""
    if df is None or df.empty:
        print("❌ 无效数据，无法分析")
        return None, None

    # 确保有足够的数据
    if len(df) < 2:
        print("⚠️ 数据不足，至少需要2年数据进行分析")
        return None, None

    # 提取元数据
    metadata = getattr(df, 'attrs', {}).get('metadata', {})
    region = metadata.get('地区', '上海市')
    time_range = metadata.get('时间', f"{df['年份'].min()}-{df['年份'].max()}年")

    # 计算衍生指标
    if '城镇居民人均消费支出(元)' in df.columns and '农村居民人均消费支出(元)' in df.columns:
        df['城乡差距(元)'] = df['城镇居民人均消费支出(元)'] - df['农村居民人均消费支出(元)']
        df['城乡差距比'] = df['城镇居民人均消费支出(元)'] / df['农村居民人均消费支出(元)']

    # 计算增长率 - 添加NaN和无穷大处理
    for col in ['全体居民人均消费支出(元)', '城镇居民人均消费支出(元)', '农村居民人均消费支出(元)']:
        if col in df.columns:
            # 替换无穷大和负无穷大为NaN
            df[f'{col}增长率(%)'] = (df[col].pct_change() * 100).replace([np.inf, -np.inf], np.nan)

    # 排序数据
    if '年份' in df.columns:
        df.sort_values('年份', inplace=True)

    # 创建图表
    figs = []

    # 调试信息
    print("\n📊 开始创建图表...")
    print(f"数据列: {df.columns.tolist()}")
    print(f"年份数据: {df['年份'].tolist()}")

    # 1. 消费支出趋势图 - 确保正确显示
    fig1 = go.Figure()
    colors = {
        '全体居民人均消费支出(元)': '#1f77b4',  # 蓝色
        '城镇居民人均消费支出(元)': '#ff7f0e',  # 橙色
        '农村居民人均消费支出(元)': '#2ca02c'  # 绿色
    }

    # 检查数据列是否存在
    required_columns = ['全体居民人均消费支出(元)', '城镇居民人均消费支出(元)', '农村居民人均消费支出(元)']
    for col in required_columns:
        if col not in df.columns:
            print(f"⚠️ 警告: 缺失数据列 '{col}'")

    # 为每个指标添加轨迹 - 使用列表形式确保数据可序列化
    for indicator in required_columns:
        if indicator in df.columns:
            print(f"📈 添加轨迹: {indicator} - {len(df[indicator])}个数据点")
            fig1.add_trace(go.Scatter(
                x=df['年份'].astype(str).tolist(),  # 转换为字符串列表
                y=df[indicator].tolist(),  # 转换为标准列表
                mode='lines+markers',
                name=indicator.replace('人均消费支出(元)', ''),
                line=dict(width=3, color=colors.get(indicator, '#000000')),
                marker=dict(size=8, symbol='circle'),
                hovertemplate=f'{indicator.split("(")[0]}: %{{y:,.0f}}元<extra></extra>'
            ))

    # 更新布局 - 使用简化布局确保显示
    fig1.update_layout(
        title=f'{region}居民人均消费支出趋势 ({time_range})',
        xaxis_title='年份',
        yaxis_title='人均消费支出（元）',
        template='plotly_white',
        height=500,
        # X轴设置 - 简化配置
        xaxis=dict(
            tickmode='array',
            tickvals=df['年份'].tolist(),
            ticktext=[str(y) for y in df['年份']],
            tickangle=-45
        ),
        # Y轴设置
        yaxis=dict(
            tickformat=',.0f',
            ticksuffix='元',
            gridcolor='#f0f0f0',
            rangemode='tozero'
        ),
        # 图例设置
        legend=dict(
            orientation='h',
            yanchor='bottom',
            y=1.02,
            xanchor='center',
            x=0.5
        )
    )

    # 确保输出目录存在
    output_dir.mkdir(parents=True, exist_ok=True)

    # 保存图表到HTML用于调试
    debug_path = output_dir / "debug_trend_chart.html"
    fig1.write_html(debug_path)
    print(f"✅ 趋势图表已保存到: {debug_path}")

    figs.append(fig1)

    # 2. 城乡差距分析
    if '城乡差距(元)' in df.columns and '城乡差距比' in df.columns:
        fig2 = go.Figure()

        # 城乡差距柱状图 - 使用列表形式
        fig2.add_trace(go.Bar(
            x=df['年份'].astype(str).tolist(),
            y=df['城乡差距(元)'].tolist(),
            name='城乡差距 (元)',
            marker_color='#d62728',
            hovertemplate='城乡差距: %{y:,.0f}元<extra></extra>'
        ))

        # 城乡差距比线图（次Y轴）- 使用列表形式
        fig2.add_trace(go.Scatter(
            x=df['年份'].astype(str).tolist(),
            y=df['城乡差距比'].tolist(),
            name='城乡差距比 (城镇/农村)',
            mode='lines+markers',
            line=dict(width=3, color='#9467bd'),
            yaxis='y2',
            hovertemplate='城乡差距比: %{y:.2f}<extra></extra>'
        ))

        fig2.update_layout(
            title=f'{region}城乡居民消费差距分析',
            xaxis_title='年份',
            yaxis_title='城乡差距 (元)',
            yaxis2=dict(
                title='城乡差距比',
                overlaying='y',
                side='right',
                range=[1, max(2.5, df['城乡差距比'].max() * 1.1)]  # 动态范围
            ),
            legend=dict(orientation='h', yanchor='bottom', y=1.02, xanchor='center', x=0.5),
            template='plotly_white',
            height=500
        )
        figs.append(fig2)

    # 3. 增长率分析
    growth_found = False
    fig3 = go.Figure()

    growth_colors = {
        '全体居民人均消费支出(元)增长率(%)': '#1f77b4',
        '城镇居民人均消费支出(元)增长率(%)': '#ff7f0e',
        '农村居民人均消费支出(元)增长率(%)': '#2ca02c'
    }

    for col in growth_colors:
        if col in df.columns:
            fig3.add_trace(go.Bar(
                x=df['年份'].astype(str).tolist(),  # 转换为字符串列表
                y=df[col].tolist(),  # 转换为标准列表
                name=col.replace('增长率(%)', ''),
                marker_color=growth_colors[col],
                hovertemplate='增长率: %{y:.1f}%<extra></extra>'
            ))
            growth_found = True

    if growth_found:
        fig3.update_layout(
            title=f'{region}居民消费支出年度增长率',
            xaxis_title='年份',
            yaxis_title='增长率 (%)',
            barmode='group',
            template='plotly_white',
            height=500
        )
        figs.append(fig3)

    return figs, df


# 4. 生成分析报告
def generate_analysis_report(df, figs, metadata, output_path):
    """生成完整的HTML分析报告"""
    print(f"\n💾 正在生成分析报告: {output_path}")

    # 确保输出目录存在
    output_path.parent.mkdir(parents=True, exist_ok=True)

    # 提取元数据
    region = metadata.get('地区', '上海市')
    data_source = metadata.get('数据来源', '国家统计局')
    time_range = metadata.get('时间', '最近数据')

    # 获取最新数据
    if '年份' in df.columns and not df.empty:
        latest_year = df['年份'].max()
        latest_data = df[df['年份'] == latest_year]
        if not latest_data.empty:
            latest_data = latest_data.iloc[0]
        else:
            latest_data = None
    else:
        latest_year = "最新"
        latest_data = None

    # 创建HTML报告
    html_content = f"""
    <!DOCTYPE html>
    <html lang="zh-CN">
    <head>
        <meta charset="UTF-8">
        <title>{region}居民消费支出分析报告</title>
        <script src="https://cdn.plot.ly/plotly-latest.min.js"></script>
        <style>
            body {{
                font-family: 'Microsoft YaHei', Arial, sans-serif;
                margin: 0;
                padding: 20px;
                background-color: #f5f7fa;
                color: #333;
            }}
            .container {{
                max-width: 1200px;
                margin: 0 auto;
                background: white;
                padding: 20px;
                border-radius: 8px;
                box-shadow: 0 0 10px rgba(0,0,0,0.1);
            }}
            h1 {{
                color: #1a3c6c;
                text-align: center;
                border-bottom: 2px solid #1a3c6c;
                padding-bottom: 15px;
                margin-bottom: 30px;
            }}
            .chart-container {{
                margin-bottom: 40px;
                padding: 15px;
                border: 1px solid #e0e0e0;
                border-radius: 8px;
                background-color: #fff;
            }}
            .chart-title {{
                font-size: 18px;
                font-weight: bold;
                margin-bottom: 15px;
                color: #2a4e8a;
            }}
            .insights {{
                background-color: #e8f4ff;
                border-left: 4px solid #1a3c6c;
                padding: 15px;
                margin: 20px 0;
                border-radius: 0 4px 4px 0;
            }}
            .insights h3 {{
                margin-top: 0;
                color: #1a3c6c;
            }}
            .conclusion {{
                background-color: #f0f8ff;
                padding: 20px;
                border-radius: 8px;
                margin-top: 30px;
            }}
            .conclusion h2 {{
                color: #1a3c6c;
                border-bottom: 1px solid #a0c4ff;
                padding-bottom: 10px;
            }}
            footer {{
                text-align: center;
                margin-top: 30px;
                color: #666;
                font-size: 14px;
            }}

            /* 响应式布局 */
            @media (max-width: 768px) {{
                .chart-container {{
                    overflow-x: auto;
                }}
                #trend-chart, #gap-chart, #growth-chart {{
                    min-width: 600px;
                }}
            }}
        </style>
    </head>
    <body>
        <div class="container">
            <h1>{region}居民消费支出分析报告</h1>

            <div class="insights">
                <h3>核心洞察</h3>
                <p>1. 2020年受疫情影响，全体居民和城镇居民消费支出出现下降</p>
                <p>2. 2023年消费支出强劲反弹，创历史新高</p>
                <p>3. 城乡消费差距呈现缩小趋势，2024年差距比降至1.70</p>
            </div>

            <!-- 趋势图 -->
            <div class="chart-container">
                <div class="chart-title">上海市居民人均消费支出趋势 (最近10年)</div>
                <div id="trend-chart"></div>
                <div class="insights">
                    <p>• 2020年消费支出因疫情下降5-7%，2021年迅速恢复</p>
                    <p>• 2023年全体居民消费支出突破5万元大关</p>
                    <p>• 农村居民消费增长更快，十年增幅达100%</p>
                </div>
            </div>

            <!-- 城乡差距图 -->
            <div class="chart-container">
                <div class="chart-title">上海市城乡居民消费差距分析</div>
                <div id="gap-chart"></div>
                <div class="insights">
                    <p>• 城乡差距绝对值在2020年达到峰值（22,744元）后开始下降</p>
                    <p>• 城乡差距比从2015年的2.29降至2024年的1.70</p>
                    <p>• 2024年农村居民消费增速快于城镇</p>
                </div>
            </div>

            <!-- 增长率图 -->
            <div class="chart-container">
                <div class="chart-title">上海市居民消费支出年度增长率</div>
                <div id="growth-chart"></div>
                <div class="insights">
                    <p>• 2021年出现报复性增长（全体+14.9%，农村+23.1%）</p>
                    <p>• 2020年受疫情影响出现负增长</p>
                    <p>• 2024年农村消费增速（5.0%）快于城镇（0.1%）</p>
                </div>
            </div>

            <div class="conclusion">
                <h2>结论与建议</h2>
                <p>1. <strong>消费恢复强劲</strong>：2021-2023年消费快速恢复，表明{region}居民消费潜力巨大</p>
                <p>2. <strong>城乡差距持续缩小</strong>：农村居民消费增速快于城镇，城乡差距比降至1.7的历史低点</p>
                <p>3. <strong>政策建议</strong>：继续加大对农村消费基础设施投入，培育新型消费增长点</p>
                <p>4. <strong>风险提示</strong>：需关注2024年城镇居民消费增长乏力（仅0.1%）的问题</p>
            </div>

            <footer>
                <p>数据来源：{data_source} | 报告生成时间：{pd.Timestamp.now().strftime('%Y年%m月%d日')}</p>
            </footer>
        </div>
    """

    # 添加图表脚本 - 确保正确渲染
    if figs:
        html_content += """
        <script>
            // 图表配置
            const chartConfigs = [
        """

        # 图表ID映射
        chart_ids = ["trend-chart", "gap-chart", "growth-chart"]

        for i, fig in enumerate(figs):
            if i < len(chart_ids) and fig:
                chart_id = chart_ids[i]

                # 使用Plotly的to_json方法获得正确的JSON格式
                chart_json = fig.to_json()

                html_content += f"""
                {{
                    id: '{chart_id}',
                    config: {chart_json}
                }},
                """

        html_content += """
            ];

            // 渲染图表
            document.addEventListener('DOMContentLoaded', function() {
                chartConfigs.forEach(item => {
                    const container = document.getElementById(item.id);
                    if (container) {
                        // 使用Plotly的react方法渲染
                        Plotly.react(
                            container, 
                            item.config.data, 
                            item.config.layout
                        );
                    }
                });
            });
        </script>
        """

    html_content += """
    </body>
    </html>
    """

    # 保存报告
    with open(output_path, 'w', encoding='utf-8') as f:
        f.write(html_content)

    print(f"✅ 分析报告已保存至: {output_path}")

    # 在报告中添加调试信息
    debug_info = f"""
    ======== 调试信息 ========
    报告生成时间: {pd.Timestamp.now().strftime('%Y-%m-%d %H:%M:%S')}
    图表数量: {len(figs) if figs else 0}
    数据行数: {len(df) if df is not None else 0}
    数据列: {df.columns.tolist() if df is not None else []}
    """
    print(debug_info)

    return True


# 主程序
def main():
    print("=" * 60)
    print("上海市居民消费支出数据分析项目")
    print("=" * 60)

    # 设置文件路径
    project_dir = Path(r"E:\Zhuo_mian\数据分析\项目\居民消费水平支出")
    data_file = project_dir / "上海市全体居民人均消费支出年度数据02.csv"
    output_file = project_dir / "上海市居民消费支出分析报告.html"

    # 创建调试目录
    debug_dir = project_dir / "debug_files"
    debug_dir.mkdir(parents=True, exist_ok=True)

    print(f"项目目录: {project_dir}")
    print(f"数据文件: {data_file}")
    print(f"输出报告: {output_file}")
    print(f"调试目录: {debug_dir}")

    # 检查文件是否存在
    if not data_file.exists():
        print(f"❌ 错误: 数据文件不存在")
        print(f"请检查路径: {data_file}")
        return

    # 加载数据
    print("\n📂 正在加载数据...")
    raw_df, metadata = load_statistics_csv(data_file)

    if raw_df is None:
        print("❌ 数据加载失败，程序终止")
        return

    # 预处理数据
    print("\n🔄 正在预处理数据...")
    clean_df = preprocess_consumption_data(raw_df, metadata, debug_dir)

    if clean_df is None:
        print("❌ 数据预处理失败，程序终止")
        return

    # 分析与可视化
    print("\n📊 正在分析数据并生成可视化...")
    figs, analyzed_df = analyze_and_visualize(clean_df, debug_dir)

    if not figs:
        print("⚠️ 部分可视化失败，但仍将继续生成报告")
    else:
        print(f"✅ 成功生成 {len(figs)} 个图表")

    # 生成报告
    print("\n📝 正在生成分析报告...")
    generate_analysis_report(analyzed_df, figs, metadata, output_file)

    print("\n✅ 分析完成！")
    print(f"请查看生成的报告: {output_file}")
    print(f"调试文件保存在: {debug_dir}")

    # 在浏览器中打开报告
    try:
        import webbrowser
        webbrowser.open(output_file.as_uri())
        print("🌐 正在浏览器中打开报告...")
    except:
        print("⚠️ 无法自动打开报告，请手动打开文件")


if __name__ == "__main__":
    # 设置更详细的错误输出
    try:
        main()
    except Exception as e:
        print(f"❌ 程序发生错误: {str(e)}")
        import traceback

        traceback.print_exc()
        sys.exit(1)